package com.carl.zeus.config.shiro;

import com.carl.zeus.model.system.SysMenu;
import com.carl.zeus.model.system.SysUser;
import com.carl.zeus.server.system.SysMenuService;
import com.carl.zeus.server.system.SysUserService;
import com.carl.zeus.util.MyDES;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * shiro身份校验核心类
 * 
 * @author 作者: zcm
 * @date 创建时间：2017年2月10日 下午3:19:48
 */


public class MyShiroRealm extends AuthorizingRealm {


	@Autowired
	private SysUserService sysUserService;
	
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	
	@Autowired
	private SysMenuService sysMenuService;
	
	//用户登录次数计数  redisKey 前缀
	private String SHIRO_LOGIN_COUNT = "shiro_login_count_";
	
	//用户登录是否被锁定    一小时 redisKey 前缀
	private String SHIRO_IS_LOCK = "shiro_is_lock_";

	/**
	 * 认证信息.(身份验证) : Authentication 是用来验证用户身份
	 * 
	 * @param
	 * @return
	 * @throws AuthenticationException
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		String username = token.getUsername();
		String password = String.valueOf(token.getPassword());
		//访问一次，计数一次
		ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();

		opsForValue.increment(SHIRO_LOGIN_COUNT + username, 1);
		//计数大于5时，设置用户被锁定一小时
		if(Integer.parseInt(opsForValue.get(SHIRO_LOGIN_COUNT + username)) >= 5){
			opsForValue.set(SHIRO_IS_LOCK + username, "LOCK");
			stringRedisTemplate.expire(SHIRO_IS_LOCK + username, 1, TimeUnit.HOURS);
		}
		if ("LOCK".equals(opsForValue.get(SHIRO_IS_LOCK + username))){
			throw new DisabledAccountException("由于密码输入错误次数大于5次，帐号已经禁止登录！");
		}

		//密码进行加密处理  明文为  password+name
		String paw = password + username;
		String pawDES = MyDES.encryptBasedDes(paw);
		// 从数据库获取对应用户名密码的用户
		SysUser user = sysUserService.findByUsernameAndPassword(username, pawDES);

		if (null == user) {
			throw new AccountException("帐号或密码不正确！");
		}else if(user.getStatus() == 0){
			throw new DisabledAccountException("此帐号已经设置为禁止登录！");
		}else{
			//更新登录时间 last login time
			user.setLastLoginTime(new Date());
			sysUserService.updateById(user);
			//清空登录计数
			opsForValue.set(SHIRO_LOGIN_COUNT + username, "0");
		}
		SecurityUtils.getSubject().getSession().setAttribute("user", user);
//		ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
//		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), credentialsSalt, getName());
		return new SimpleAuthenticationInfo(user, password, getName());
	}

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		if (principals == null) {
			throw new AuthorizationException("Principal对象不能为空");
		}
		SysUser user = (SysUser) getAvailablePrincipal(principals);
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		//如果登陆用户是admin,拥有所有权限
		if(user.getUsername().equals("admin")){
			List<SysMenu> resList = sysMenuService.selectMenuUrlAllList();
			for (SysMenu menu : resList) {
				info.addStringPermission(menu.getPerms());
			}
		}else{
			List<SysMenu> resUserList = sysMenuService.selectMenuListByUserId(user.getId());
			for (SysMenu resUser : resUserList) {
				info.addStringPermission(resUser.getPerms());
			}
		}
//		System.out.println("权限认证方法：MyShiroRealm.doGetAuthorizationInfo()");
//		SysUser user = (SysUser) SecurityUtils.getSubject().getPrincipal();
//		Long userId = user.getId();
//		SimpleAuthorizationInfo info =  new SimpleAuthorizationInfo();
//		//根据用户ID查询角色（role），放入到Authorization里。
//		Map<String, Object> map = new HashMap<>();
//		map.put("user_id", userId);
//		List<SysRole> roleList = sysRoleService.selectByMap(map);
//		Set<String> roleSet = new HashSet<>();
//		for(SysRole role : roleList){
//			roleSet.add(role.getType());
//		}
//		Set<String> roleSet = new HashSet<>();
//		roleSet.add("100002");
//		info.setRoles(roleSet);
//		//根据用户ID查询权限（permission），放入到Authorization里。
//		List<SysPermission> permissionList = sysPermissionService.selectByMap(map);
//		Set<String> permissionSet = new HashSet<String>();
//		for(SysPermission Permission : permissionList){
//			permissionSet.add(Permission.getName());
//		}
//		Set<String> permissionSet = new HashSet<String>();
//		permissionSet.add("权限添加");
//		permissionSet.add("权限删除");
//		info.setStringPermissions(permissionSet);
        return info;
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo(){
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null){
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

}
